﻿#region 참조 네임스페이스

using System;
using System.Runtime.InteropServices;

#endregion

namespace Skying.Windows.API
{
	/// <summary>
	/// Windows 라이브러리 파일 중 kernel32.dll에 대한 메서드를 제공한다.
	/// </summary>
	public static class Kernel32
	{
		#region LoadLibraryEx

		/// <summary>
		/// 호출된 프로세스의 주소 공간으로 특정 모듈을 로드한다.
		/// </summary>
		/// <param name="filename">로드하려는 모듈의 파일명을 지정한다.</param>
		/// <param name="reserved">[예약됨]</param>
		/// <param name="flags"></param>
		/// <returns></returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
		public static extern IntPtr LoadLibraryEx(string filename, IntPtr reserved, LoadLibraryFlags flags);

		/// <summary>
		/// <see cref="Skying.Windows.API.Kernel32.LoadLibraryEx"/> 메서드에 전달되는 플래그를 열거한다.
		/// </summary>
		[Flags]
		public enum LoadLibraryFlags
		{
			/// <summary>
			/// <para>이 플래그가 사용되면 실행 가능한 모듈은 DLL이라는 가정하에 시스템은 DllMain과 스레드 초기화와 제거를 실행하지 않는다.</para>
			/// <para>또한, 시스템은 해당 모듈에 의해 참조되는 추가적인 모듈들을 로드하지 않는다.</para>
			/// <para>[주의] 이 플래그는 사용하면 안 된다. 이 플래그는 안정성을 보장하지 못한다.</para>
			/// <para>만약 데이터나 리소스에 접근하려고 한다면 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 혹은 LOAD_LIBRARY_AS_IMAGE_RESOURCE 혹은 둘을 동시에 적용하라.</para>
			/// </summary>
			DONT_RESOLVE_DLL_REFERENCES = 0x00000001,

			/// <summary>
			/// <para>시스템은 모듈을 AppLocker 규칙으로 점검하지 않는다. 또한 DLL에 Software Restriction Polices를 적용한다.</para>
			/// <para>이 플래그는 설치하는 동안 추출된 DLL들을 실행해야만 하는 설치 프로그램에서 사용하기를 추천한다.</para>
			/// </summary>
			LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,

			/// <summary>
			/// <para>모듈의 파일이 데이터 파일일 경우 시스템은 그 파일을 호출된 프로세스의 가상 주소 공간으로 매핑한다.</para>
			/// <para>이럴 경우, 어떤 것도 실행되지 않으며 매핑된 파일을 실행한 준비만 한다.</para>
			/// <para>그러므로, GetModuleFileName, GetModuleHandle 혹은 GetProcAddress와 같은 메서드들을 호출할 수 없다.</para>
			/// <para>이 플래그를 사용하는 것은 읽기 전용 메모리에 쓰기를 시도하여 접근 위반을 야기할 수도 있다.</para>
			/// <para>파일로부터 메시지나 리소스 등을 추출하려는 목적으로 사용하기에 알맞다.</para>
			/// </summary>
			LOAD_LIBRARY_AS_DATAFILE = 0x00000002,

			/// <summary>
			/// <para>DLL 파일이 호출된 프로세스에 대해 독점적인 쓰기 접근으로 열린다는 점을 제외하고는 LOAD_LIBRARY_AS_DATAFILE와 유사하다.</para>
			/// <para>이 플래그에 의해 DLL이 사용되고 있는 동안에는 다른 프로세스들은 쓰기 접근으로 DLL을 열 수 없다.</para>
			/// </summary>
			LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,

			/// <summary>
			/// <para>이 플래그가 사용될 경우, 시스템은 해당 파일을 이미지 파일로써 프로세스의 가상 주소 공간에 매핑한다.</para>
			/// <para>그러나, 로더는 정적 임포트들을 로드하지 않거나 다른 통상의 초기화 과정을 실행하지 않는다.</para>
			/// <para>파일로부터 메시지나 리소스 등을 추출하려는 목적으로 사용하기에 알맞다.</para>
			/// </summary>
			LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,

			/// <summary>
			/// <para>DLL과 그것의 의존성들에 대한 애플리케이션의 설치 경로를 찾을 수 있다. 표준 검색 경로 내에서의 디렉토리들은 찾아지지 않는다.</para>
			/// <para>이 플래그는 LOAD_WITH_ALTERED_SEARCH_PATH 플래그와 함께 사용될 수 없다.</para>
			/// </summary>
			LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,

			/// <summary>
			/// <para>이 플래그는 LOAD_LIBRARY_SEARCH_APPLICATION_DIR, LOAD_LIBRARY_SEARCH_SYSTEM32, 그리고 LOAD_LIBRARY_SEARCH_USER_DIRS 플래그들의 합성 플래그이다.</para>
			/// <para>표준 검색 경로 내의 디렉토리들은 찾아지지 않는다.</para>
			/// <para>이 플래그는 LOAD_WITH_ALTERED_SEARCH_PATH 플래그와 함께 사용될 수 없다.</para>
			/// <para>이 플래그는 애플리케이션이 그것의 DLL 검색 경로 내에서 포함해야 하는 디렉토리들의 최대 추천 개수를 나타낸다.</para>
			/// </summary>
			LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,

			/// <summary>
			/// <para>DLL을 포함하는 디렉토리가 임시적으로 DLL의 의존성들을 검색하는 디렉토리 목록의 처음에 포함된다.</para>
			/// <para>표준 검색 경로 내의 디렉토리들은 찾아지지 않는다.</para>
			/// <para>이 플래그는 LOAD_WITH_ALTERED_SEARCH_PATH 플래그와 함께 사용될 수 없다.</para>
			/// </summary>
			LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,

			/// <summary>
			/// <para>DLL과 그것의 의존성들에 대한 %windows%\system32 경로가 검색되어 진다.</para>
			/// <para>표준 검색 경로 내의 디렉토리들은 찾아지지 않는다.</para>
			/// <para>이 플래그는 LOAD_WITH_ALTERED_SEARCH_PATH 플래그와 함께 사용될 수 없다.</para>
			/// </summary>
			LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,

			/// <summary>
			/// <para>AllDllDirectory 혹은 SetDllDirectory 메서드를 통해 추가된 디렉토리들이 DLL과 그것의 의존성들에 대해서 검색되어 진다.</para>
			/// <para>한 개 이상의 디렉토리가 추가되어질 경우, 검색되어 진 디렉토리들의 순서는 특성화되지 않는다.</para>
			/// <para>표준 검색 경로 내의 디렉토리들은 찾아지지 않는다.</para>
			/// </summary>
			LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,

			/// <summary>
			/// <para>이 플래그가 사용되고 fileName 파라메터가 절대 경로를 가르킬 경우, 시스템은 alternate 파일 검색 전략을 사용하게 된다.</para>
			/// <para>alternate 파일 검색 전략은 특정 모듈을 로드하도록 하는 실행가능한 연관 모듈들을 찾기 위한 Remark 섹션내에서 규정되어 진다.</para>
			/// <para>이 플래그가 사용되지 않거나 fileName 파라메터가 절대 경로가 아닌 경우, 시스템은 표준 검색 전략을 사용하게 된다.</para>
			/// <para>표준 검색 전략은 특정 모듈이 로드되도록 하는 실행 가능한 모듈들을 찾기 위한 Remark 섹션 내에서 규정되어 진다.</para>
			/// <para>이 플래그는 LOAD_LIBRARY_SEARCH 플래그와 함께 사용될 수 없다.</para> 
			/// </summary>
			LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
		}

		#endregion

		#region FreeLibrary

		/// <summary>
		/// 로드된 다이나믹 링크 라이브러리 모듈을 해제한다.
		/// </summary>
		/// <param name="module">로드된 라이브러리 모듈의 핸들을 지정한다.</param>
		/// <returns>함수가 성공할 경우 true, 실패할 경우 false가 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern bool FreeLibrary(IntPtr module);

		#endregion

		#region EnumResourceTypes

		/// <summary>
		/// 바이너리 모듈 내의 리소스 타입들을 나열한다.
		/// </summary>
		/// <param name="handle">리소스 타입들을 검색할 모듈의 핸들을 설정한다.</param>
		/// <param name="function">각기 나열될 리소스 타입들에 대해 호출될 콜백 대리자를 지정한다.</param>
		/// <param name="lParam">콜백 대리자로 전달될 애플리케이션 정의 파라메터를 설정한다.</param>
		/// <returns>성공적으로 진행되면 true, 그렇지 않으면 false가 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern bool EnumResourceTypes(IntPtr handle, EnumResourceTypesDelegate function, IntPtr lParam);
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern bool EnumResourceTypes(IntPtr handle, EnumResourceTypesDelegateEx function, object lParam);

		/// <summary>
		/// <see cref="Skying.Windows.API.Kernel32.EnumResourceTypes"/>와 <see cref="Skying.Windows.API.Kernel32.EnumResourceTypesEx"/> 메서드와 함께 사용되는 애플리케이션 정의 콜백 함수를 나타낸다.
		/// </summary>
		/// <param name="handle">
		/// <para>리소스 타입들을 열거하기 위한 리소스들이 포함되어 있는 실행 가능한 파일의 모듈에 대한 핸들이다.</para>
		/// <para>이 파라메터가 null일 경우, 함수는 현재 프로세스를 생성하는데 사용된 모듈 내의 리소스 타입들을 열거한다.</para>
		/// </param>
		/// <param name="type">열거된 리소스의 타입을 나타낸다.</param>
		/// <param name="lParam">
		/// <para><see cref="Skying.Windows.API.Kernel32.EnumResourceTypes"/> 혹은 <see cref="Skying.Windows.API.Kernel32.EnumResourceTypesEx"/>로 전달될 애플리케이션 정의 파라메터를 나타낸다.</para>
		/// <para>이 파라메터는 오류 검출에 이용될 수 있다.</para>
		/// </param>
		/// <returns>열거가 계속될 경우 true, 열거가 멈출 경우 false가 반환된다.</returns>
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate bool EnumResourceTypesDelegate(IntPtr handle, IntPtr type, IntPtr lParam);
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate bool EnumResourceTypesDelegateEx(IntPtr handle, IntPtr type, object lParam);

		#endregion

		#region EnumResourceNames

		/// <summary>
		/// 바이너리 모듈 내에 명시된 타입의 리소스들을 열거한다.
		/// </summary>
		/// <param name="module">리소스들을 검색할 모듈의 핸들을 설정한다.</param>
		/// <param name="type">열거되어질 리소스 타입에 대한 이름을 나타낸다.</param>
		/// <param name="callback">각기 열거되어진 리소스 이름 혹은 아이디에 대해 호출되어지는 콜백 대리자를 나타낸다.</param>
		/// <param name="lParam">콜백 대리자에 의해 전달될 애플리케이션 정의 파라메터를 나타낸다.</param>
		/// <returns>성공적으로 끝나면 true, 명시된 리소스 타입을 찾지 못하거나 다른 이유에 의해 함수가 실패할 경우 false가 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern bool EnumResourceNames(IntPtr module, IntPtr type, EnumResourceNamesDelegate callback, IntPtr lParam);
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern bool EnumResourceNames(IntPtr module, IntPtr type, EnumResourceNamesDelegateEx callback, object lParam);

		/// <summary>
		/// <para><see cref="Skying.Windows.API.Kernel32.EnumResourceNames"/>와 <see cref="Skying.Windows.API.Kernel32.EnumResourceNamesEx"/> 메서드와 함께 사용되는 애플리케이션 정의 콜백 함수를 나타낸다.</para>
		/// <para>이 함수는 리소스 타입과 그에 대한 이름을 전달받는다.</para>
		/// </summary>
		/// <param name="module">
		/// <para>리소스 타입들을 열거하기 위한 리소스들이 포함되어 있는 실행 가능한 파일의 모듈에 대한 핸들이다.</para>
		/// <para>이 파라메터가 null일 경우, 함수는 현재 프로세스를 생성하는데 사용된 모듈 내의 리소스 타입들을 열거한다.</para>
		/// </param>
		/// <param name="type">열거된 리소스의 타입을 나타낸다.</param>
		/// <param name="name">열거된 리소스의 이름을 나타낸다.</param>
		/// <param name="lParam">
		/// <para><see cref="Skying.Windows.API.Kernel32.EnumResourceNames"/> 혹은 <see cref="Skying.Windows.API.Kernel32.EnumResourceNamesEx"/>로 전달될 애플리케이션 정의 파라메터를 나타낸다.</para>
		/// <para>이 파라메터는 오류 검출에 이용될 수 있다.</para>
		/// </param>
		/// <returns>열거가 계속될 경우 true, 열거가 멈출 경우 false가 반환된다.</returns>
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate bool EnumResourceNamesDelegate(IntPtr module, IntPtr type, IntPtr name, IntPtr lParam);
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate bool EnumResourceNamesDelegateEx(IntPtr module, IntPtr type, IntPtr name, object lParam);

		#endregion

		#region FindResource

		/// <summary>
		/// 특정 이름과 타입에 대한 리소스를 찾는다.
		/// </summary>
		/// <param name="module">리소스가 포함되어 있는 실행 파일 혹은 MUI 파일의 모듈의 핸들을 설정한다.</param>
		/// <param name="name">리소스 이름의 핸들을 설정한다.</param>
		/// <param name="type">리소스 타입의 핸들을 설정한다.</param>
		/// <returns>
		/// <para>함수가 성공할 경우, 찾고자 하는 리소스의 정보 블럭의 핸들이 반환된다. 리소스의 핸들을 얻기 위해서는 <see cref="Skying.Windows.API.Kernel32.LoadResource"/>로 반환된 핸들을 넘겨야 한다.</para>
		/// <para>함수가 실패할 경우, null이 반환된다.</para>
		/// </returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern IntPtr FindResource(IntPtr module, IntPtr name, IntPtr type);

		/// <summary>
		/// 특정 이름과 타입, 언어에 대한 리소스를 찾는다.
		/// </summary>
		/// <param name="module">리소스가 포함되어 있는 실행 파일 혹은 MUI 파일의 모듈의 핸들을 설정한다.</param>
		/// <param name="name">리소스 이름의 핸들을 설정한다.</param>
		/// <param name="type">리소스 타입의 핸들을 설정한다.</param>
		/// <param name="language">리소스의 언어를 설정한다.</param>
		/// <returns>
		/// <para>함수가 성공할 경우, 찾고자 하는 리소스의 정보 블럭의 핸들이 반환된다. 리소스의 핸들을 얻기 위해서는 <see cref="Skying.Windows.API.Kernel32.LoadResource"/>로 반환된 핸들을 넘겨야 한다.</para>
		/// <para>함수가 실패할 경우, null이 반환된다.</para>
		/// </returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern IntPtr FindResourceEx(IntPtr module, IntPtr type, IntPtr name, ushort language);

		#endregion

		#region LoadResource

		/// <summary>
		/// 메모리 내에서 특정 리스소의 첫번째 byte의 포인터를 얻기 위한 핸들을 찾는다.
		/// </summary>
		/// <param name="module">리소스를 포함하는 실행 파일의 모듈의 핸들을 설정한다.</param>
		/// <param name="resInfo"><see cref="Skying.Windows.API.Kernel32.FindResource"/> 혹은 <see cref="Skying.Windows.API.Kernel32.FindResourceEx"/>로부터 반환된 리소스 정보 블럭의 핸들을 설정한다.</param>
		/// <returns>함수가 성공할 경우, 리소스와 관련있는 데이터의 핸들이 반환된다. 함수가 실패할 경우, null이 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern IntPtr LoadResource(IntPtr module, IntPtr resInfo);

		#endregion

		#region LockResource

		/// <summary>
		/// 메모리 내에서 특정 리소스에 대한 포인터를 찾는다.
		/// </summary>
		/// <param name="resData">접근하려는 리소스의 핸들을 설정한다. <see cref="Skying.Windows.API.LoadResource"/>로부터 반환받는다.</param>
		/// <returns>로드된 리소스가 사용 가능하면 리소스의 첫번째 byte의 포인터가 반환된다. 그렇지 않으면 null이 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern IntPtr LockResource(IntPtr resData);

		#endregion

		#region SizeOfResource

		/// <summary>
		/// 특정 리소스에 대한 바이트 크기를 검색한다.
		/// </summary>
		/// <param name="module">리소스를 포함하는 실행 파일 모듈의 핸들을 설정한다.</param>
		/// <param name="resInfo">리소스 정보 블럭의 핸들을 설정한다. 리소스 정보 블럭의 핸들은 <see cref="Skying.Windows.API.Kernel32.FindResource"/> 혹은 <see cref="Skying.Windows.API.Kernel32.FindResourceEx"/>를 통해 얻을 수 있다.</param>
		/// <returns>함수가 성공할 경우, 리소스에 대한 바이트 크기가 반환된다. 함수가 실패할 경우, 0가 반환된다.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
		public static extern int SizeofResource(IntPtr module, IntPtr info);

		#endregion
	}
}